#ifndef _DESCRIPTOR_H_
#define _DESCRIPTOR_H_

#include "base.h"

#define RPL0						0x0
#define RPL1						0x1
#define RPL2						0x2
#define RPL3						0x3

#define INDEX_GDT				0x0
#define INDEX_LDT				0x1

#define KERNEL_CODE_INDEX		0x01
#define KERNEL_DATA_INDEX		0x02
#define TSS_INDEX				0x03
#define USER_CODE_INDEX			0x04
#define USER_DATA_INDEX			0x05

#define DESC_MAX				(USER_DATA_INDEX + 1)
#define GDT_LEN				(DESC_MAX * 8)


#define KERNEL_CODE_SEL		((KERNEL_CODE_INDEX << 3) | INDEX_GDT |RPL0 )
#define KERNEL_DATA_SEL		((KERNEL_DATA_INDEX << 3) | INDEX_GDT | RPL0)

#define USER_CODE_SEL		((USER_CODE_INDEX << 3) |  INDEX_GDT |RPL3)
#define USER_DATA_SEL		((USER_DATA_INDEX << 3) |  INDEX_GDT |RPL3)


/*
  *  descriptor privilege 
  */
#define DPL0			0
#define DPL1			1
#define DPL2			2
#define DPL3			3

#define GRANU_4K	1
#define GRANU_1B	0

#define CODE_32		1
#define DATA_32		1
#define STACK_32	1


#define DATA_R_W				0x2
#define STACK_R_W				0x6

#define CODE_C0			0xA

#define CALL_GATE_386	0xC
#define INTR_GATE_386	0xE


struct seg_desc_attr{
	uint_8 type:4;
	uint_8 dt:1;
	uint_8 dpl:2;
	uint_8 p:1;

	uint_8 seg_limit_h:4;
	uint_8 avl:1;
	uint_8 resv:1;
	uint_8 d:1;
	uint_8 g:1;	
};


struct seg_desc{
	uint_16 seg_limit_l;
	uint_16 seg_base_l;
	uint_8 seg_base_m;
	struct seg_desc_attr  seg_attr;
	uint_8 seg_base_h;
};


#define dummy_desc()\
{\
	.seg_limit_l = NULL,\
	.seg_base_l = NULL,\
	.seg_base_m = NULL,\
	.seg_attr = {\
		.type =NULL , .dt =NULL , .dpl =NULL , .p =NULL ,\
		.seg_limit_h = NULL, .avl =NULL , .resv =NULL , .d =NULL , .g = NULL},\
	.seg_base_h = NULL \
}

#define kernel_code_desc()\
{\
	.seg_limit_l = 0xFFFF,\
	.seg_base_l = 0x0000,\
	.seg_base_m = 0x00,\
	.seg_attr = {\
		.type = CODE_C0, .dt =0x1 , .dpl =DPL0 , .p =0x1 ,\
		.seg_limit_h = 0xF, .avl =0x0 , .resv =0x0 , .d = CODE_32, .g = GRANU_4K},\
	.seg_base_h = 0x00 \
}

#define kernel_data_desc()\
{\
	.seg_limit_l = 0xFFFF,\
	.seg_base_l = 0x0000,\
	.seg_base_m = 0x00,\
	.seg_attr = {\
		.type = DATA_R_W, .dt =0x1 , .dpl =DPL0 , .p =0x1 ,\
		.seg_limit_h =0xF , .avl =0x0 , .resv =0x0 , .d = DATA_32, .g = GRANU_4K},\
	.seg_base_h = 0x00 \
}

#define tss_desc()\
{\
	.seg_limit_l = 0xFFFF,\
	.seg_base_l = 0x0000,\
	.seg_base_m = 0x00,\
	.seg_attr = {\
		.type = NULL, .dt =0x0 , .dpl =DPL0 , .p =0x1 ,\
		.seg_limit_h = NULL, .avl =0x0 , .resv =0x0 , .d = NULL, .g = GRANU_1B},\
	.seg_base_h = 0x00 \
}

#define user_code_desc()\
{\
	.seg_limit_l = 0xFFFF,\
	.seg_base_l = 0x0000,\
	.seg_base_m = 0x00,\
	.seg_attr = {\
		.type = CODE_C0, .dt =0x1 , .dpl =DPL3 , .p =0x1 ,\
		.seg_limit_h = 0xF, .avl =0x0 , .resv =0x0 , .d = CODE_32, .g = GRANU_4K},\
	.seg_base_h = 0x00 \
}

#define user_data_desc()\
{\
	.seg_limit_l = 0xFFFF,\
	.seg_base_l = 0x0000,\
	.seg_base_m = 0x00,\
	.seg_attr = {\
		.type = DATA_R_W, .dt =0x1 , .dpl =DPL3 , .p =0x1 , \
		.seg_limit_h = 0xF, .avl =0x0 , .resv =0x0 , .d = DATA_32, .g = GRANU_4K},\
	.seg_base_h = 0x00 \
}



struct gate_desc_attr{
	uint_8 resv;

	uint_8 type:4;
	uint_8 s:1;
	uint_8 dpl:2;
	uint_8 p:1;
};

struct gate_desc{
	uint_16 gate_offset_l;
	uint_16 gate_selector;
	struct gate_desc_attr gate_attr;
	uint_16 gate_offset_h;
};


#define INTR_GATE_32	0xE

#define intr_gate_attr_set()\
{\
	.resv = 0x0,\
	.type = INTR_GATE_386,\
	.s = 0x0,\
	.dpl = DPL0,\
	.p = 0x1\
}

#define intr_gate_set()\
{\
	.gate_offset_l = 0,\
	.gate_selector = 0,\
	.gate_attr = intr_gate_attr_set(),\
	.gate_offset_h = 0\
}

#define IO_BITMAP_SIZE	32

struct tss_t{
	unsigned short  back_link,__blh;
	unsigned long   esp0;
	unsigned short  ss0,__ss0h;
	unsigned long   esp1;     
	unsigned short  ss1,__ss1h;
	unsigned long   esp2;
	unsigned short  ss2,__ss2h;
	unsigned long   __cr3;   
	unsigned long   eip;
	unsigned long   eflags;
	unsigned long   eax,ecx,edx,ebx;
	unsigned long   esp;
	unsigned long   ebp;
	unsigned long   esi;
	unsigned long   edi;
	unsigned short  es, __esh;
	unsigned short  cs, __csh;
	unsigned short  ss, __ssh;
	unsigned short  ds, __dsh;
	unsigned short  fs, __fsh;
	unsigned short  gs, __gsh;
	unsigned short  ldt, __ldth;
	unsigned short  trace, bitmap;
	unsigned long   io_bitmap[IO_BITMAP_SIZE+1];

    /*
     * pads the TSS to be cacheline-aligned (size is 0x100)
     */
	unsigned long __cacheline_filler[5];
};

#define TSS_LEN		sizeof(struct tss_t)

EXTERN struct gate_desc idt_start;
EXTERN struct tss_t tss;
#endif

